package camaras;

import java.nio.DoubleBuffer;

import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;

import figuras.PuntoVector;

public class Camara {

	public static final int ESQUINA = 1;

	public static final int CENITAL = 2;

	public static final int LATERAL = 3;

	public static final int FRONTAL = 4;

	private PuntoVector eye;
	private PuntoVector look;
	private PuntoVector up;
	private PuntoVector u; // eje X de la camara
	private PuntoVector v; // eje y de la camara
	private PuntoVector n; // eye z de la camara
	private double left, right, top, bottom;
	private double cerca;
	private double lejos;
	private double anguloVision, proporcion;

	private GL gl;
	private GLU glu;

	public Camara() {
	}

	public Camara(PuntoVector ojo, PuntoVector look, PuntoVector up, int flag,
			double l, double r, double b, double t, double n, double f,
			double a, double p, GL gl, GLU glu) {
		left = l;
		right = r;
		bottom = b;
		top = t;
		cerca = n;
		lejos = f;
		anguloVision = a;
		proporcion = p;
		this.n = null;
		this.u = null;
		this.v = null;
		this.eye = null;
		this.look = null;
		this.up = null;
		this.gl = gl;
		this.glu = glu;
		setView(ojo, look, up);
		setView();
		setProyection(flag);
	}

	public void setView(PuntoVector eye, PuntoVector look, PuntoVector up) {
		this.eye = new PuntoVector(eye);
		this.look = new PuntoVector(look);
		this.up = new PuntoVector(up);
		n = look.obtenVector(eye);
		n.normaliza();
		u = up.productoVectorial(n);
		u.normaliza();
		v = n.productoVectorial(u);
		v.normaliza();
	}

	public void setView() {
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();
		glu.gluLookAt(eye.getX(), eye.getY(), eye.getZ(), look.getX(), look
				.getY(), look.getZ(), up.getX(), up.getY(), up.getZ());
	}

	public void setProyection(int flag) {
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glLoadIdentity();
		if (flag == 0)
			gl.glOrtho(left, right, bottom, top, cerca, lejos);
		else
			glu.gluPerspective(anguloVision, proporcion, cerca, lejos);
	}

	public void setModelViewMatrix() {
		double dx = -eye.productoEscalar(u);
		double dy = -eye.productoEscalar(v);
		double dz = -eye.productoEscalar(n);
		DoubleBuffer matrizVista = DoubleBuffer.allocate(16);
		matrizVista.array()[0] = u.getX();
		matrizVista.array()[1] = v.getX();
		matrizVista.array()[2] = n.getX();
		matrizVista.array()[3] = 0.0;
		matrizVista.array()[4] = u.getY();
		matrizVista.array()[5] = v.getY();
		matrizVista.array()[6] = n.getY();
		matrizVista.array()[7] = 0.0;
		matrizVista.array()[8] = u.getZ();
		matrizVista.array()[9] = v.getZ();
		matrizVista.array()[10] = n.getZ();
		matrizVista.array()[11] = 0.0;
		matrizVista.array()[12] = dx;
		matrizVista.array()[13] = dy;
		matrizVista.array()[14] = dz;
		matrizVista.array()[15] = 1.0;
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();
		gl.glLoadMatrixd(matrizVista);
	}

	public void roll(double ang) {
		float coseno = (float) Math.cos(2 * Math.PI * ang / 360.0);
		float seno = (float) Math.sin(2 * Math.PI * ang / 360.0);
		PuntoVector t = new PuntoVector(u);
		u.setX(coseno * t.getX() - seno * v.getX());
		u.setY(coseno * t.getY() - seno * v.getY());
		u.setZ(coseno * t.getZ() - seno * v.getZ());
		v.setX(seno * t.getX() + coseno * v.getX());
		v.setY(seno * t.getY() + coseno * v.getY());
		v.setZ(seno * t.getZ() + coseno * v.getZ());
		setModelViewMatrix();
	}

	public void pitch(double ang) {
		float coseno = (float) Math.cos(2 * Math.PI * ang / 360.0);
		float seno = (float) Math.sin(2 * Math.PI * ang / 360.0);
		PuntoVector t = new PuntoVector(v);
		v.setX(coseno * t.getX() - seno * n.getX());
		v.setY(coseno * t.getY() - seno * n.getY());
		v.setZ(coseno * t.getZ() - seno * n.getZ());
		n.setX(seno * t.getX() + coseno * n.getX());
		n.setY(seno * t.getY() + coseno * n.getY());
		n.setZ(seno * t.getZ() + coseno * n.getZ());
		setModelViewMatrix();
	}

	public void yaw(double ang) {
		float coseno = (float) Math.cos(2 * Math.PI * ang / 360.0);
		float seno = (float) Math.sin(2 * Math.PI * ang / 360.0);
		PuntoVector t = new PuntoVector(u);
		u.setX(coseno * t.getX() + seno * n.getX());
		u.setY(coseno * t.getY() + seno * n.getY());
		u.setZ(coseno * t.getZ() + seno * n.getZ());
		n.setX(-seno * t.getX() + coseno * n.getX());
		n.setY(-seno * t.getY() + coseno * n.getY());
		n.setZ(-seno * t.getZ() + coseno * n.getZ());
		setModelViewMatrix();
	}

	public void desliza(float delU, float delV, float delN) {
		this.eye.setX(this.eye.getX() + delU);
		this.eye.setY(this.eye.getY() + delV);
		this.eye.setZ(this.eye.getZ() + delN);

		setModelViewMatrix();
	}

	public void lateral() {
		PuntoVector ojo = new PuntoVector(300.0f, 0.0f, 0.0f, 1);
		PuntoVector mira = new PuntoVector(0.0f, 0.0f, 0.0f, 1);
		PuntoVector arriba = new PuntoVector(0.0f, 1.0f, 0.0f, 0);
		setView(ojo, mira, arriba);
		setView();
		setModelViewMatrix();
	}

	public void frontal() {
		PuntoVector ojo = new PuntoVector(0.0f, 0.0f, 300.0f, 1);
		PuntoVector mira = new PuntoVector(0.0f, 0.0f, 0.0f, 1);
		PuntoVector arriba = new PuntoVector(0.0f, 1.0f, 0.0f, 0);
		setView(ojo, mira, arriba);
		setView();
		setModelViewMatrix();
	}

	public void cenital() {
		PuntoVector ojo = new PuntoVector(0.0f, 300.0f, 0.0f, 1);
		PuntoVector mira = new PuntoVector(0.0f, 0.0f, 0.0f, 1);
		PuntoVector arriba = new PuntoVector(-1.0f, 0.0f, -1.0f, 0);
		setView(ojo, mira, arriba);
		setView();
		setModelViewMatrix();
	}

	public void esquina() {
		PuntoVector ojo = new PuntoVector(300.0f, 300.0f, 300.0f, 1);
		PuntoVector mira = new PuntoVector(0.0f, 0.0f, 0.0f, 1);
		PuntoVector arriba = new PuntoVector(0.0f, 1.0f, 0.0f, 0);
		setView(ojo, mira, arriba);
		setView();
		setModelViewMatrix();
	}

	public void vista(PuntoVector ojo, PuntoVector mira,
			PuntoVector arriba) {
		setView(ojo, mira, arriba);
		setView();
		setModelViewMatrix();
	}
}
